package com.zx.flow.core.execute.eventhandler;

import com.zx.flow.api.config.FlowConfig;
import com.zx.flow.api.config.FlowConfigListener;
import com.zx.flow.api.config.FlowConfigNode;
import com.zx.flow.api.dict.FlowDict.Event;
import com.zx.flow.api.dict.FlowDict.ListenerType;
import com.zx.flow.api.execute.common.Convert;
import com.zx.flow.api.execute.model.FlowContext;
import com.zx.flow.api.execute.request.FlowParamListener;
import com.zx.flow.api.execute.response.FlowResult;
import com.zx.flow.api.listener.FlowEvent;
import com.zx.flow.api.util.SendUtil;
import com.zx.flow.api.util.Util;
import com.zx.flow.core.execute.EventHandler;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.CollectionUtils;

/**
 * 事件处理器【流程->触发监听事件】
 */
@Slf4j
public class EventFlowListenerHandler extends EventHandler<FlowParamListener> {

    private static final ExecutorService pool = Executors.newFixedThreadPool(10);

    @Override
    public boolean in(FlowContext flow, FlowParamListener param) {
        return flow != null;
    }

    @Override
    public FlowResult on(FlowContext flow, FlowParamListener param) {
        FlowConfig config = this.getFlowConfig(flow.getFlowConfigCode(), flow.getFlowConfigId());
        FlowConfigNode eventNode = config.getNode(param.getNode().getNodeCurrentCode());
        List<FlowConfigListener> listeners = eventNode.getListeners();

        if (CollectionUtils.isEmpty(listeners)) {
            log.info("执行事件处理, 没有listener, flowId={}, nodeCode={}, event={}",
                    param.getId(), eventNode.getCode(), param.getEvent().getCode());
            return FlowResult.invalid("没有listener", flow);
        }
        Event event = param.getEvent();
        listeners = listeners.stream()
                .filter(lis -> Util.findHas(lis.getEvents(), event.getCode()))
                .collect(Collectors.toList());
        if (CollectionUtils.isEmpty(listeners)) {
            log.info("执行事件处理, 没有listener, flowId={}, nodeCode={}, event={}",
                    param.getId(), eventNode.getCode(), param.getEvent().getCode());
            return FlowResult.invalid("没有listener", flow);
        }

        doListeners(flow, param, listeners);
        return FlowResult.ok(flow);
    }

    private void doListeners(FlowContext flow, FlowParamListener param, List<FlowConfigListener> listeners) {
        // 构建请求参数
        FlowEvent flowEvent = Convert.to(flow, param.getNode(), param.getEvent());

        log.info("执行事件处理, 执行listener, flowId={}, listenerNum={}", flow.getId(), listeners.size());
        for (FlowConfigListener listener : listeners) {
            if (Objects.equals(ListenerType.wc.getCode(), listener.getType())) {
                SendUtil.wechat(flow, listener.getWcId());

            } else if (Objects.equals(ListenerType.dd.getCode(), listener.getType())) {
                SendUtil.dingding(flow, listener.getDdId());

            } else if (Objects.equals(ListenerType.fs.getCode(), listener.getType())) {
                SendUtil.feishu(flow, listener.getFsId());

            } else if (Objects.equals(ListenerType.sms.getCode(), listener.getType())) {
                SendUtil.sms(flow, listener.getWcId());

            } else if (Objects.equals(ListenerType.mq.getCode(), listener.getType())) {
                SendUtil.mq(flow, listener.getMqTopic(), listener.getMqTag());

            } else if (Objects.equals(ListenerType.http.getCode(), listener.getType())) {
                // 异步执行
                if (listener.isAsync()) {
                    pool.execute(() -> SendUtil.httpPost(flowEvent, listener.getUrl(), listener.getConnectionTimeout(),
                            listener.getReadTimeout(), listener.getReplay()));
                } else {
                    // 同步执行
                    SendUtil.httpPost(flowEvent, listener.getUrl(), listener.getConnectionTimeout(),
                            listener.getReadTimeout(), listener.getReplay());
                }
            }
        }
    }
}
